/*
 * WidgetRoot.cpp
 *
 *	Author: stravant
 *	Description:
 *		
 */

#include "WidgetRoot.h"
#include "../core/EventLoop.h"
#include "../ui/Window.h"
#include "../core/Bits.h"

namespace tbt {

WidgetRoot::WidgetRoot(): mWindow(nullptr) {
	setRoot(this);
	setBackgroundColor(fx::Color(217.0/255.0, 212.0/255.0, 204.0/255.0));
}

WidgetRoot::~WidgetRoot() {
}

//mouse grab has to enter the mouse to the grab-ing
//widget if it isn't allready the mouse-over widget
void WidgetRoot::setMouseGrab(Ref<Widget> widget) {
	class ActionCallCrossing: public Action, public MouseEvent {
	public:
		ActionCallCrossing(Ref<Widget> trg, Event::Type ty, Event::Flag flags, const IVec& pos):
			MouseEvent(ty, flags, pos), mTarget(trg) {}
		void run() {mTarget->onEvent_Crossing(*this); }
	private:
		Ref<Widget> mTarget;
	};

	mMouseGrab = widget;
	if (widget != mPrevTarget) {
		if (mPrevTarget && mPrevTarget != this) {
			EventLoop::current()->queueAction(
				new ActionCallCrossing(mPrevTarget,
						Event::kEvtMouseLeave,
						mWindow->getInput().getCurrentFlags(),
						mWindow->getInput().getMousePos()));
		}
		mPrevTarget = widget;
		if (mPrevTarget && mPrevTarget != this) {
			EventLoop::current()->queueAction(
				new ActionCallCrossing(mPrevTarget,
						Event::kEvtMouseEnter,
						mWindow->getInput().getCurrentFlags(),
						mWindow->getInput().getMousePos()));
		}
	}
}

fx::Context* WidgetRoot::getContext() const {
	return mWindow->getContext();
}

void WidgetRoot::onResized(const IVec& newSize) {
	setSize(newSize);
	onLayout();
}

void WidgetRoot::onRepaint(const IRect& region) {
	auto c = mWindow->getContext();
	onPaint(region, c);
}

void WidgetRoot::onEvent_Button(const MouseButtonEvent& e) {
	if (mMouseGrab) {
		if (mMouseGrab != this)
			mMouseGrab->onEvent_Button(e);
	} else {
		Ref<Widget> w = findWidgetForPoint(e.getPos());
		if (w && w != this)
			w->onEvent_Button(e);
	}
}

void WidgetRoot::onEvent_Key(const KeyEvent& e) {
	if (onGlobalKey(e))
		return;

	if (mKeyGrab && mKeyGrab != this) {
		mKeyGrab->onEvent_Key(e);
	}
}

void WidgetRoot::onEvent_Scroll(const MouseWheelEvent& e) {
	if (mMouseGrab) {
		mMouseGrab->onEvent_Scroll(e);
	} else {
		Ref<Widget> w = findWidgetForPoint(e.getPos());
		if (w && w != this)
			w->onEvent_Scroll(e);
	}
}

void WidgetRoot::onEvent_Motion(const MouseEvent& e) {
	if (mMouseGrab) {
		if (mMouseGrab != this)
			mMouseGrab->onEvent_Motion(e);
	} else {
		Ref<Widget> w = findWidgetForPoint(e.getPos());
		if (w != mPrevTarget) {
			if (mPrevTarget && mPrevTarget != this) {
				MouseEvent leave(Event::kEvtMouseLeave,
									mWindow->getInput().getCurrentFlags(),
									e.getPos());
				mPrevTarget->onEvent_Crossing(leave);
			}
			mPrevTarget = w;
			if (w && w != this) {
				MouseEvent enter(Event::kEvtMouseEnter,
									mWindow->getInput().getCurrentFlags(),
									e.getPos());
				w->onEvent_Crossing(enter);
			}
		}
		if (w && w != this)
			w->onEvent_Motion(e);
	}
}

void WidgetRoot::onEvent_Crossing(const MouseEvent& e) {
	//todo: maybe have to translate this to motion?

}

void WidgetRoot::onPaint(const IRect& region, fx::Context* c) {
	DRect mr = getBounds().to<double>();
	c->save();
	c->rectangle(region.to<double>());
	c->clip();

	//clear out corners to transparent
	c->save();
	c->setOperator(fx::Context::kOpSource);
	c->setSourceColor(0.0, 0.0, 0.0, 0.0);
	c->rectangle(DRect(mr.x(), mr.y(), kCornerRadius, kCornerRadius));
	c->fill();
	c->rectangle(DRect(mr.x()+mr.width()-kCornerRadius, mr.y(),
			kCornerRadius, kCornerRadius));
	c->fill();
	c->rectangle(DRect(mr.x(), mr.y()+mr.height()-kCornerRadius,
			kCornerRadius, kCornerRadius));
	c->fill();
	c->rectangle(DRect(mr.x()+mr.width()-kCornerRadius, mr.y()+mr.height()-kCornerRadius,
			kCornerRadius, kCornerRadius));
	c->fill();
	c->setOperator(fx::Context::kOpOver);
	c->restore();

	//fill in the background
	//c->setSourceColor(0.2, 0.2, 0.2);
	c->setSourceColor(getBackgroundColor());
	c->roundedRectangle(mr, kCornerRadius);
	c->fill();

	//draw the top highlight
	c->setLineWidth(1);
	//c->setSourceColor(0.35, 0.35, 0.35)
	c->setSourceColor(getBackgroundColor().lighter(0.2));
	c->newPath();
	c->moveTo(DVec(mr.x()+1.5, mr.bottom()-kCornerRadius+1.5));
	c->lineTo(DVec(mr.x()+1.5, mr.y()+kCornerRadius-1.5));
	c->lineTo(DVec(mr.x()+kCornerRadius-1.5, mr.y()+1.5));
	c->lineTo(DVec(mr.right()-kCornerRadius+1.5, mr.y()+1.5));
	c->stroke();

	//draw the bottom highlight
	c->setLineWidth(1);
	//c->setSourceColor(0.15, 0.15, 0.15);
	c->setSourceColor(getBackgroundColor().darker(0.2));
	c->newPath();
	c->moveTo(DVec(mr.right()-1.5, mr.y()+kCornerRadius-1.5));
	c->lineTo(DVec(mr.right()-1.5, mr.bottom()-kCornerRadius+1.5));
	c->lineTo(DVec(mr.right()-kCornerRadius+1.5, mr.bottom()-1.5));
	c->lineTo(DVec(mr.x()+kCornerRadius-1.5, mr.bottom()-1.5));
	c->stroke();

	c->restore();
	//draw children
	Widget::onPaint(region, c);
}

Ref<Window> WidgetRoot::getWindow() const {
	return mWindow;
}

}
